// Author: wsfuyibing <682805@qq.com>
// Date: 2025-04-28

package guest

import (
    "context"
    "fmt"
    "math/rand"
    "server/app/errs"
    "server/app/http/logics/common/requests"
    "server/app/http/models"
    "server/app/http/services"
    "server/app/kind"
    "server/app/lib/authorizer"
    "strings"
    "time"
)

// Login
// 登录公共方法.
//
// 适用于 微信, 抖音 等不同小程序.
type Login struct{}

// InitLoginedForBind
// 绑定交互.
func (o *Login) InitLoginedForBind(ctx context.Context, oauth *models.Oauth) (logined *Logined, err error) {
    return &Logined{
        AuthId:   oauth.Id,
        UserCode: oauth.UserCode,
        Mobile:   oauth.OpenMobile.Mask(),
    }, nil
}

// InitLoginedForUser
// 直接登录.
func (o *Login) InitLoginedForUser(ctx context.Context, oauth *models.Oauth, device *requests.DeviceRequest) (logined *Logined, err error) {
    var (
        has     bool
        service = services.NewUsersService()
        user    *models.Users
    )

    // 1. 查询用户.
    if user, has, err = service.Dao.GetById(ctx, oauth.UserId); err != nil {
        err = errs.ErrDatabaseQuery
        return
    }

    // 2. 用户不存在.
    if !has {
        err = errs.ErrUserNotFound
        return
    }

    // 3. 账号受限.
    if !user.State.IsNormal() {
        err = errs.ErrUserRestricted
        return
    }

    // 4. 登录日志.
    if device != nil {
        if err = o.InitLoginedDevice(ctx, oauth, device); err != nil {
            return
        }
    }

    // 5. 正常登录.
    logined = &Logined{Mobile: oauth.OpenMobile.Mask()}
    logined.Token, logined.Seconds, err = authorizer.New().Build(authorizer.NewAuthentication(user))
    return
}

// InitLoginedDevice
// 记录登录日志.
func (o *Login) InitLoginedDevice(ctx context.Context, oauth *models.Oauth, device *requests.DeviceRequest) (err error) {
    if device != nil && oauth.UserId > 0 {
        _, err = services.NewUserLoginsService().Dao.AddByStruct(ctx, &models.UserLogins{
            OauthId:   oauth.Id,
            UserId:    oauth.UserId,
            Kind:      oauth.Kind,
            Type:      device.Type,
            Code:      strings.ToUpper(device.Code),
            Brand:     strings.ToUpper(device.Brand),
            Model:     strings.ToUpper(device.Model),
            OsName:    strings.ToUpper(device.OsName),
            OsVersion: device.OsVersion,
        })
    }
    return
}

// InitOauth
// 初始授权.
//
// 从 oauth 表查询三方(微信、抖音等)授权数据, 若目标数据不存在则创建.
func (o *Login) InitOauth(ctx context.Context, kind kind.OauthKind, appId, openId string) (oauth *models.Oauth, err error) {
    var (
        has     bool
        service = services.NewOauthService()
    )

    // 1. 查询数据.
    if oauth, has, err = service.Dao.GetByMap(ctx, map[string]any{
        "kind":    kind,
        "app_id":  appId,
        "open_id": openId,
    }); err != nil {
        err = errs.ErrDatabaseQuery
        return
    }

    // 2. 创建数据.
    //    只有在目标数据不存在时才创建, 反之则复用.
    if !has {
        if oauth, err = service.Dao.AddByStruct(ctx, &models.Oauth{
            UserCode: o.InitOauthCode(),
            Kind:     kind,
            AppId:    appId,
            OpenId:   openId,
        }); err != nil {
            err = errs.ErrDatabaseQuery
        }
    }
    return
}

// InitOauthCode
// 创建唯一授权码.
func (o *Login) InitOauthCode() (str string) {
    t := time.Now()
    s := rand.Int31n(9999999)
    e := rand.Int31n(9999999)
    str = fmt.Sprintf(`T%dR%07d%07d`, t.UnixMicro(), s, e)
    return
}
